(function() {
  var module,
     __indexOf = [].indexOf || function(item) {
		for (var i = 0, l = this.length; i < l; i++) {
			if (i in this && this[i] === item)
				return i;
		}
		return -1;
	};

  module = angular.module('angularBootstrapNavTree', []);

  module.directive('abnTree', ['$timeout', '$log', function($timeout, $log) {
	  var log = $log.getInstance('tree');
      return {
        restrict: 'E',
        template: "<ul class=\"nav nav-list nav-pills nav-stacked abn-tree\">\n " +
        		" <li ng-repeat=\"row in tree_rows | filter:{visible:true} track by row.branch.uid\" " +
        		"ng-animate=\"'abn-tree-animate'\" " +
        		"ng-class=\"'level-' + {{ row.level }} + (row.branch.selected ? ' active':'') + ' ' +row.classes.join(' ')\" class=\"abn-tree-row\">" +
        		"<a ng-click=\"user_clicks_branch(row.branch)\">" +
        		"<i ng-class=\"row.tree_icon\" ng-click=\"row.branch.expanded = !row.branch.expanded\" class=\"indented tree-icon\"> </i>" +
        		"<span class=\"indented tree-label\">{{ row.label }} </span>" +
        		"</a></li>\n</ul>",
        replace: true,
        scope: {
          treeData: '=',
          onSelect: '&',
          initialSelection: '@',
          treeControl: '='
        },
		link : function(scope, element, attrs) {
			var expand_all_parents, expand_level, for_all_ancestors, for_each_branch, get_parent, n, on_treeData_change, select_branch, selected_branch, tree;
			scope.multipleSelected = !!eval(attrs.multipleSelected);
			if (attrs.iconExpand == null) {
				attrs.iconExpand = 'icon-plus  glyphicon glyphicon-plus  fa fa-plus';
			}
			if (attrs.iconCollapse == null) {
				attrs.iconCollapse = 'icon-minus glyphicon glyphicon-minus fa fa-minus';
			}
			if (attrs.iconLeaf == null) {
				attrs.iconLeaf = 'icon-file  glyphicon glyphicon-file  fa fa-file';
			}
			if (attrs.expandLevel == null) {
				attrs.expandLevel = '3';
			}
			expand_level = parseInt(attrs.expandLevel, 10);
			if (!scope.treeData) {
				log.debug('no treeData defined for the tree!');
				return;
			}
			if (scope.treeData.length == null) {
				if (treeData.label != null) {
					scope.treeData = [ treeData ];
				} else {
					log.debug('treeData should be an array of root branches');
					return;
				}
			}
			for_each_branch = function(f) {
				var do_f, root_branch, _i, _len, _ref, _results;
				do_f = function(branch, level) {
					var child, _i, _len, _ref, _results;
					f(branch, level);
					if (branch.children != null) {
						_ref = branch.children;
						_results = [];
						for (_i = 0, _len = _ref.length; _i < _len; _i++) {
							child = _ref[_i];
							_results.push(do_f(child, level + 1));
						}
						return _results;
					}
				};
				_ref = scope.treeData;
				_results = [];
				for (_i = 0, _len = _ref.length; _i < _len; _i++) {
					root_branch = _ref[_i];
					_results.push(do_f(root_branch, 1));
				}
				return _results;
			};
			selected_branch = [];
			select_branch = function(branch) {
				var i;
				if (!branch) {
					return;
				}
				if (!branch.selected) {
					branch.selected = true;
					if (scope.multipleSelected) {
						selected_branch.push(branch);
					} else if (!scope.multipleSelected) {
						angular.forEach(selected_branch, function(b) {
							b.selected = false;
						});
						selected_branch = [ branch ];
					}
				} else {
					for (i = 0; i < selected_branch.length; i++) {
						if (selected_branch[i] == branch) {
							branch.selected = false;
							selected_branch.splice(i, 1);
							break;
						}
					}
				}
				expand_all_parents(branch);
				if (branch.onSelect != null) {
					return $timeout(function() {
						return branch.onSelect(branch);
					});
				} else {
					if (scope.onSelect != null) {
						return $timeout(function() {
							return scope.onSelect({branch : branch});
						});
					}
				}
			};
			scope.user_clicks_branch = function(branch) {
				return select_branch(branch);
			};
			get_parent = function(child) {
				var parent;
				parent = void 0;
				if (child.parent_uid) {
					for_each_branch(function(b) {
						if (b.uid === child.parent_uid) {
							return parent = b;
						}
					});
				}
				return parent;
			};
			for_all_ancestors = function(child, fn) {
				var parent;
				parent = get_parent(child);
				if (parent != null) {
					fn(parent);
					return for_all_ancestors(parent, fn);
				}
			};
			expand_all_parents = function(child) {
				return for_all_ancestors(child, function(b) {
					return b.expanded = true;
					});
			};
			scope.tree_rows = [];
			on_treeData_change = function() {
				var add_branch_to_list, root_branch, _i, _len, _ref, _results;
				for_each_branch(function(b, level) {
					if (!b.uid) {
						return b.uid = "" + Math.random();
					}
				});
				for_each_branch(function(b) {
					var child, _i, _len, _ref, _results;
					if (angular.isArray(b.children)) {
						_ref = b.children;
						_results = [];
						for (_i = 0, _len = _ref.length; _i < _len; _i++) {
							child = _ref[_i];
							_results.push(child.parent_uid = b.uid);
						}
						return _results;
					}
				});
				scope.tree_rows = [];
				for_each_branch(function(branch) {
					var child, f;
					if (branch.children) {
						if (branch.children.length > 0) {
							f = function(e) {
								if (typeof e === 'string') {
									return {
										label : e,
										children : []
									};
								} else {
									return e;
								}
							};
							return branch.children = (function() {
								var _i, _len, _ref, _results;
								_ref = branch.children;
								_results = [];
								for (_i = 0, _len = _ref.length; _i < _len; _i++) {
									child = _ref[_i];
									_results.push(f(child));
								}
								return _results;
							})();
						}
					} else {
						return branch.children = [];
					}
				});
				add_branch_to_list = function(level, branch, visible) {
					var child, child_visible, tree_icon, _i, _len, _ref, _results;
					if (branch.expanded == null) {
						branch.expanded = false;
					}
					if (branch.classes == null) {
						branch.classes = [];
					}
					if (!branch.noLeaf && (!branch.children || branch.children.length === 0)) {
						tree_icon = attrs.iconLeaf;
						if (__indexOf.call(branch.classes, "leaf") < 0) {
							branch.classes.push("leaf");
						}
					} else {
						if (branch.expanded) {
							tree_icon = attrs.iconCollapse;
						} else {
							tree_icon = attrs.iconExpand;
						}
					}
					scope.tree_rows.push({
						level : level,
						branch : branch,
						label : branch.label,
						classes : branch.classes,
						tree_icon : tree_icon,
						visible : visible
					});
					if (branch.children != null) {
						_ref = branch.children;
						_results = [];
						for (_i = 0, _len = _ref.length; _i < _len; _i++) {
							child = _ref[_i];
							child_visible = visible && branch.expanded;
							_results.push(add_branch_to_list(level + 1, child, child_visible));
						}
						return _results;
					}
				};
				_ref = scope.treeData;
				_results = [];
				for (_i = 0, _len = _ref.length; _i < _len; _i++) {
					root_branch = _ref[_i];
					_results.push(add_branch_to_list(1, root_branch, true));
				}
				return _results;
			};
			scope.$watch('treeData', on_treeData_change, true);
			if (attrs.initialSelection != null) {
				for_each_branch(function(b) {
					if (b.label === attrs.initialSelection) {
						return $timeout(function() {
							return select_branch(b);
						});
					}
				});
			}
			n = scope.treeData.length;
			for_each_branch(function(b, level) {
				b.level = level;
				return b.expanded = b.level < expand_level;
			});
			if (scope.treeControl != null) {
				if (angular.isObject(scope.treeControl)) {
					tree = scope.treeControl;
					tree.expand_all = function() {
						return for_each_branch(function(b, level) {
							return b.expanded = true;
						});
					};
					tree.collapse_all = function() {
						return for_each_branch(function(b, level) {
							return b.expanded = false;
						});
					};
					tree.get_first_branch = function() {
						n = scope.treeData.length;
						if (n > 0) {
							return scope.treeData[0];
						}
					};
					tree.select_first_branch = function() {
						var b;
						b = tree.get_first_branch();
						return tree.select_branch(b);
					};
					tree.get_selected_branch = function() {
						return selected_branch;
					};
					tree.get_parent_branch = function(b) {
						return get_parent(b);
					};
					tree.select_branch = function(b) {
						select_branch(b);
						return b;
					};
					tree.get_children = function(b) {
						return b.children;
					};
					tree.select_parent_branch = function(b) {
						var p;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							p = tree.get_parent_branch(b[0]);
							if (p != null) {
								tree.select_branch(p);
								return p;
							}
						}
					};
					tree.add_branch = function(parent, new_branch) {
						if (parent != null) {
							parent.children.push(new_branch);
							parent.expanded = true;
						} else {
							scope.treeData.push(new_branch);
						}
						return new_branch;
					};
					tree.add_root_branch = function(new_branch) {
						tree.add_branch(null, new_branch);
						return new_branch;
					};
					tree.expand_branch = function(b) {
						if (b == null) {
							b = selected_branch;
						}
						if (b != null) {
							angular.forEach(b, function(branch){
								branch.expanded = true;
							});
							return b;
						}
					};
					tree.collapse_branch = function(b) {
						if (b == null) {
							b = selected_branch;
						}
						if (b != null) {
							angular.forEach(b, function(branch){
								branch.expanded = false;
							});
							return b;
						}
					};
					tree.get_siblings = function(b) {
						var p, siblings;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							p = tree.get_parent_branch(b[0]);
							if (p) {
								siblings = p.children;
							} else {
								siblings = scope.treeData;
							}
							return siblings;
						}
					};
					tree.get_next_sibling = function(b) {
						var i, siblings;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							siblings = tree.get_siblings(b[0]);
							n = siblings.length;
							i = siblings.indexOf(b[0]);
							if (i < n) {
								return siblings[i + 1];
							}
						}
					};
					tree.get_prev_sibling = function(b) {
						var i, siblings;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							siblings = tree.get_siblings(b[0]);
							n = siblings.length;
							i = siblings.indexOf(b[0]);
							if (i > 0) {
								return siblings[i - 1];
							}
						}
					};
					tree.select_next_sibling = function(b) {
						var next;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							next = tree.get_next_sibling(b[0]);
							if (next != null) {
								return tree.select_branch(next);
							}
						}
					};
					tree.select_prev_sibling = function(b) {
						var prev;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							prev = tree.get_prev_sibling(b[0]);
							if (prev != null) {
								return tree.select_branch(prev);
							}
						}
					};
					tree.get_first_child = function(b) {
						var _ref;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							if (((_ref = b[0].children) != null ? _ref.length : void 0) > 0) {
								return b[0].children[0];
							}
						}
					};
					tree.get_closest_ancestor_next_sibling = function(b) {
						var next, parent;
						next = tree.get_next_sibling(b);
						if (next != null) {
							return next;
						} else {
							parent = tree.get_parent_branch(b);
							return tree.get_closest_ancestor_next_sibling(parent);
						}
					};
					tree.get_next_branch = function(b) {
						var next;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							next = tree.get_first_child(b[0]);
							if (next != null) {
								return next;
							} else {
								next = tree.get_closest_ancestor_next_sibling(b[0]);
								return next;
							}
						}
					};
					tree.select_next_branch = function(b) {
						var next;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							next = tree.get_next_branch(b[0]);
							if (next != null) {
								tree.select_branch(next);
								return next;
							}
						}
					};
					tree.last_descendant = function(b) {
						var last_child;
						if (b == null) {
							return;
						}
						n = b.children.length;
						if (n === 0) {
							return b;
						} else {
							last_child = b.children[n - 1];
							return tree.last_descendant(last_child);
						}
					};
					tree.get_prev_branch = function(b) {
						var parent, prev_sibling;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							prev_sibling = tree.get_prev_sibling(b[0]);
							if (prev_sibling != null) {
								return tree.last_descendant(prev_sibling);
							} else {
								parent = tree.get_parent_branch(b[0]);
								return parent;
							}
						}
					};
					return tree.select_prev_branch = function(b) {
						var prev;
						if (b == null) {
							b = selected_branch;
						} else if (!angular.isArray(b)) {
							b = [b];
						}
						if (b != null && b.length == 1) {
							prev = tree.get_prev_branch(b[0]);
							if (prev != null) {
								tree.select_branch(prev);
								return prev;
							}
						}
					};
				}
			}
		}
      };
    }
  ]);

}).call(this);
